Skip to content

refactor: limit auto-merge duplicate siblings to metaprogramming attributes#4539

Draft
raineorshine wants to merge 1 commit into
mainfrom
raineorshine-refactor-remove-auto-merge-duplicates
Draft

refactor: limit auto-merge duplicate siblings to metaprogramming attributes#4539
raineorshine wants to merge 1 commit into
mainfrom
raineorshine-refactor-remove-auto-merge-duplicates

Conversation

@raineorshine

Copy link
Copy Markdown
Contributor

#3621

Summary

Auto-merge of duplicate siblings previously fired unconditionally in the moveThought reducer (drag & drop, indent/outdent, collapse/uncategorize, importText). When a thought was moved into a context that already contained a sibling with the same value, the two were merged and the source thought deleted — causing normal duplicate thoughts to silently disappear (e.g. #3621).

This narrows the merge gate so it only fires within metaprogramming-attribute contexts, where hierarchical merging of attribute subtrees (=children, =style, =pin, …) is required so a context never ends up with two of the same attribute. Normal duplicate siblings now coexist.

Change

Single surgical gate change in src/actions/moveThought.ts:

const isMetaMerge = isAttribute(sourceThought.value) || !!destinationContext?.some(isAttribute)
const duplicateThought =
  !sameContext && !skipMerge && sourceThought.value !== '' && isMetaMerge ? duplicateSubthought() : null
  • isAttribute(sourceThought.value) — merges the attribute node itself when moved onto a context that already has it.
  • destinationContext.some(isAttribute) — destination is inside a meta subtree; drives the hierarchical recursion (mergeThoughts moves each descendant back through moveThought, staying inside the meta subtree so duplicates merge all the way down).
  • Existing guards preserved: sameContext (rerank), skipMerge (swapParent), empty-thought guard (Empty thought in a series of copied thoughts is not pasted on the destination #4448).

The merge machinery (mergeThoughts.ts, action export, swapParent skipMerge, importText collapse trick) is otherwise unchanged.

Tests

Notes

  • Archive nuance (accepted): =archive is an attribute, so archiving duplicate thoughts still merges (no regression). A stricter "normal thoughts never merge on archive" is a possible follow-up.

Verification

  • yarn lint clean, yarn test green (1423 passed).

…ibutes

Auto-merge of duplicate siblings previously fired unconditionally in
moveThought, causing normal duplicate thoughts to silently disappear when
moved onto the same parent (e.g. #3621). Narrow the merge gate so it only
fires within metaprogramming-attribute contexts, where hierarchical merging
of attribute subtrees (=children, =style, etc.) is required. Normal duplicate
siblings now coexist.

Update moveThought/importText/swapNote/uncategorize tests: convert
merge-mechanics coverage to meta-attribute versions and add normal-duplicate
coexistence tests including the #3621 regression.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Vercel preview: https://em-fy2h8fiyh-cybersemics.vercel.app

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant